package service;

import dao.inte.ConfigurationRepository;
import dao.inte.PasswordResetRepository;
import dao.inte.UserRepository;
import domain.PasswordReset;
import domain.User;
import org.springframework.transaction.annotation.Transactional;
import service.mail.Mailer;
import service.velocity.VelocityService;

import javax.inject.Inject;

public class PasswordResetServiceImpl implements PasswordResetService {

    @Inject
    ConfigurationRepository configurationRepository;
    @Inject
    UserRepository userRepository;
    @Inject
    PasswordResetRepository passwordResetRepository;
    @Inject
    private Mailer mailer;
    private VelocityService velocityService;

    public PasswordResetServiceImpl() {
    }

    public PasswordResetServiceImpl(UserRepository userRepository, PasswordResetRepository passwordResetRepository, Mailer mailer, VelocityService velocityService) {
        this.userRepository = userRepository;
        this.passwordResetRepository = passwordResetRepository;
        this.mailer = mailer;
        this.velocityService = velocityService;
    }

    @Transactional
    public void generateNewPassword(String login, String email, String key) throws Exception {
        User user = userRepository.findByLogin(login);
        PasswordReset passwordReset = passwordResetRepository.findByKey(key);

        if (user == null || !user.getCompanyEmail().equalsIgnoreCase(email) || !user.equals(passwordReset.getUser())) {
            throw new Exception("login or email or key is wrong.");
        }

        String password = randomString(10, 15);
        user.setPassword(password);
        sendPasswordMail(user, password);

        userRepository.save(user);
        passwordResetRepository.delete(passwordReset);

    }

    @Transactional
    public String requestPasswordReset(String login, String email) throws Exception {
        User user = userRepository.findByLogin(login);
        if (user == null || !user.getCompanyEmail().equalsIgnoreCase(email)) {
            throw new Exception("login or email is wrong.");
        }
        PasswordReset reset = createPasswordResetKey(user);
        sendMailForRequestPasswordReset(user, reset.getRandomKey());
        return reset.getRandomKey();
    }

    private PasswordReset createPasswordResetKey(User user) throws Exception {
        PasswordReset reset = new PasswordReset(user, 100, 150);
        int i = 0;
        while (passwordResetRepository.findByKey(reset.getRandomKey()) != null) {
            i++;
            reset = new PasswordReset(user, 100, 150);
            if (i == 10) {
                throw new Exception();
            }
        }
        passwordResetRepository.save(reset);
        return reset;
    }

    public boolean checkPasswordResetKey(String key) {
        if (passwordResetRepository.findByKey(key) != null) {
            return true;
        }
        return false;
    }

    private void sendMailForRequestPasswordReset(User user, String key) throws Exception {
        String[] recipients = new String[1];
        recipients[0] = user.getCompanyEmail();
        mailer.postMail(recipients, configurationRepository.getConfig().getPasswordResetRequestMailSubject(), velocityService.getPasswordResetRequestMail(user, key), configurationRepository.getConfig().getAdministratorEmail());
    }


    private void sendPasswordMail(User user, String randomPassword) throws Exception {
        String[] recipients = new String[1];
        recipients[0] = user.getCompanyEmail();
        mailer.postMail(recipients, configurationRepository.getConfig().getPasswordResetMailSubject(), velocityService.getPasswordResetMail(user, randomPassword), configurationRepository.getConfig().getAdministratorEmail());
    }

    private Integer randomInt(int min, int max) {
        return (int) (Math.random() * (max - min) + min);
    }

    private String randomString(int min, int max) {
        int num = randomInt(min, max);
        byte b[] = new byte[num];
        for (int i = 0; i < num; i++) {
            b[i] = (byte) randomInt('a', 'z').intValue();
        }
        return new String(b);
    }

    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void setPasswordResetRepository(PasswordResetRepository passwordResetRepository) {
        this.passwordResetRepository = passwordResetRepository;
    }

    public void setMailer(Mailer mailer) {
        this.mailer = mailer;
    }

    public void setVelocityService(VelocityService velocityService) {
        this.velocityService = velocityService;
    }
}
